package centralizedme;

import javax.swing.JTextField;
import java.io.*;
import java.util.HashMap;

/**
 * Most of the RdfModel, RdfProperty, and RdfClass classes have been abstracted
 * away from foaf. This class will try to tie those pieces together. Mainly
 * it contains methods relating to building a foaf rdf model.
 *
 * @author palexander
 */
public class FoafLogic {
    // model to store rdf data
    RdfModel model;
    // special PersonalProfileDocument rdf class for foaf
    RdfClass ppd;
    // Person class for foaf
    FoafPerson person;

    /**
     * Takes a hashtable of components and populates a model.
     * @param components    <code>JTextField</code> components from ui.
     * @return              <code>RdfModel</code> built for foaf with user input.
     */
    public RdfModel buildModel(HashMap<String, JTextField> components) {
        // start a new model
        model = new RdfModel();
        ppd = new FoafPersonalProfileDocument(new FoafMaker(),
            new FoafPrimaryTopic());
        person = new FoafPerson();

        // get JTextField components from hashtable
        JTextField firstName = components.get("foaf:givenname");
        JTextField lastName = components.get("foaf:family_name");
        JTextField title = components.get("foaf:title");
        JTextField nick = components.get("foaf:nick");
        JTextField homepage = components.get("foaf:homepage");
        JTextField openId = components.get("foaf:openid");
        JTextField email = components.get("foaf:mbox");

        if (firstName.getText().length() > 0
                && lastName.getText().length() > 0) {
            person.add(new FoafName(firstName.getText()
                    + " " + lastName.getText()));
            person.add(new FoafGivenName(firstName.getText()));
            person.add(new FoafFamilyName(lastName.getText()));
        }

        if (nick.getText().length() > 0) {
            person.add(new FoafNick(nick.getText()));
        }

        if (openId.getText().length() > 0) {
            person.add(new FoafOpenId(openId.getText()));
        }

        if (homepage.getText().length() > 0) {
            person.add(new FoafHomePage(homepage.getText()));
        }

        if (title.getText().length() > 0) {
            person.add(new FoafTitle(title.getText()));
        }

        if (email.getText().length() > 0) {
            person.add(new FoafMbox(email.getText()));
        }

        model.add(ppd);
        model.add(person);
        return model;
    }

    /**
     * Read in a FOAF-formatted file and parse for data about the person.
     * This ignores "header"-type information and as such relies on the particular
     * format of FOAF that is used in this application.
     * @param file  <code>File</code> object from a file selector dialog.
     * @return      HashMap with properties found in the file.
     * @throws centralizedme.NoPropertyFound    Throws when a property doesn't
     * match our known properties.
     */
    public HashMap<String, String> foafFileRead(File file) throws NoPropertyFound {
        model = new RdfModel();
        ppd = new FoafPersonalProfileDocument(new FoafMaker(),
            new FoafPrimaryTopic());
        person = new FoafPerson();

        // hashtable to store info for textfields in ui
        HashMap<String, String> properties = new HashMap<String, String>();

        try {
            BufferedReader in = new BufferedReader(new FileReader(file));
            String line;
            boolean parseable = false;
            while ((line = in.readLine()) != null) {
                // check to see if we're at the end of the parsable section
                if (line.equalsIgnoreCase("</foaf:Person>")) {
                    parseable = false;
                }
                // if we're in the midst of the parseable section, handle text
                if (parseable == true) {
                    line = line.trim();
                    // special handling of email addresses
                    if (line.startsWith("<foaf:mbox")) {
                        String[] split = line.split("<| |mailto:|\"");
                        personBuilder(split[1], split[4]);
                        properties.put(split[1], split[4]);
                    } else {
                        String[] split = line.split("<|>");
                        personBuilder(split[1], split[2]);
                        properties.put(split[1], split[2]);
                    }
                }
                // check to see if we're at the beginning of the parseable section
                if (line.equalsIgnoreCase("<foaf:Person rdf:ID=\"me\">")) {
                    parseable = true;
                }
            }
            in.close();
        } catch (FileNotFoundException ex) {
            System.err.println(ex);
        } catch (IOException ioe) {
            System.err.println(ioe);
        }
        return properties;
    }

    /**
     * Build a person class by adding properties.
     * @param prop  Name of the property to add.
     * @param data  Data the property should store.
     * @throws centralizedme.NoPropertyFound
     */
    private void personBuilder(String prop, String data)
        throws NoPropertyFound {
        final String NAME = "foaf:name";
        final String GIVEN_NAME = "foaf:givenname";
        final String FAMILY_NAME = "foaf:family_name";
        final String TITLE = "foaf:title";
        final String NICK = "foaf:nick";
        final String HOMEPAGE = "foaf:homepage";
        final String OPENID = "foaf:openid";
        final String EMAIL = "foaf:mbox";

        if (prop.equalsIgnoreCase(NAME)) {
            person.add(new FoafName(data));
            return;
        }

        if (prop.equalsIgnoreCase(GIVEN_NAME)) {
            person.add(new FoafGivenName(data));
            return;
        }

        if (prop.equalsIgnoreCase(FAMILY_NAME)) {
            person.add(new FoafFamilyName(data));
            return;
        }

        if (prop.equalsIgnoreCase(TITLE)) {
            person.add(new FoafTitle(data));
            return;
        }

        if (prop.equalsIgnoreCase(NICK)) {
            person.add(new FoafNick(data));
            return;
        }

        if (prop.equalsIgnoreCase(HOMEPAGE)) {
            person.add(new FoafHomePage(data));
            return;
        }

        if (prop.equalsIgnoreCase(OPENID)) {
            person.add(new FoafOpenId(data));
            return;
        }

        if (prop.equalsIgnoreCase(EMAIL)) {
            person.add(new FoafMbox(data));
            return;
        }

        // made it this far, throw a custom exception
        throw new NoPropertyFound();
    }

    /**
     * Save a FOAF file matching the user's input
     * @param components    JTextField objects with data for the FOAF model
     * @param file          <code>File</code> object from file chooser dialog.
     */
    public void saveFoafFile(HashMap<String, JTextField> components, File file) {
        // build current model
        buildModel(components);

        try {
            BufferedWriter out = new BufferedWriter(new FileWriter(file));
            out.write(model.toString());
            out.close();
        } catch (FileNotFoundException ex) {
            System.err.println(ex);
        } catch (IOException ioe) {
            System.err.println(ioe);
        }
    }
}
